// 匹配 id="app" id='app' id=app
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
//匹配标签名  <my-header></my-header>
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`;
// 匹配特殊的标签 <my:header></my:header>
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
// 匹配标签开头 <div
const startTagOpen = new RegExp(`^<${qnameCapture}`);
// 匹配标签结尾 > />
const startTagClose = /^\s*(\/?)>/;
//匹配大标签结尾 </div>
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`);

/*
<div id="app" style="color: red;font-size: 20px;">
    你好，{{ name }}
    <span class="text" style="color: green">{{age}}</span>
  </div>
*/




function parseHtmlToAst(html){
    let text,
    root,
    currentParent,
    stack = [];
    while(html){
        let textEnd = html.indexOf('<'); // 找到第一个<
        
        // 如果第一个字符是<
        if (textEnd === 0){ 
            const startTagMatch = parseStartTag(); // 解析开始标签

            if (startTagMatch){
                start(startTagMatch.tarName,startTagMatch.attrs)
                continue; // 继续解析下一个标签
            }
            // 匹配 结束标签
            const endTagMatch = html.match(endTag);
            if (endTagMatch){
                advance(endTagMatch[0].length); // 截取html，删除已经匹配过的标签
                end(endTagMatch[1]); // 结束标签
                continue; // 继续解析下一个标签
            }
 
        }
        // 匹配文本节点
        // 如果 textEnd > 0， 说明还有其他标签节点，但是标签节点前面还有文本节点
        if (textEnd > 0){
            text = html.substring(0,textEnd); // 截取文本节点 (因为end中的>已经删除了。textEnd匹配到下一个<截取到这个字符之前的文本)
            
        }
        // 判断 text 文本节点是否为空
        if (text){
            advance(text.length); // 截取html，删除已经匹配过的文本
            chars(text) // 解析文本节点
        }

    }

    

    function parseStartTag(){
        const start = html.match(startTagOpen); // 匹配开始标签
        let end;
        let attr;
        if(start){
            const match = {
                tarName:start[1],
                attrs:[]
            }
            advance(start[0].length); // 截取html，删除已经匹配过的标签
            //后面字符不是结束标签 >，并且能匹配到属性 id="app"
            while(!(end = html.match(startTagClose)) && (attr = html.match(attribute))){
                console.log(attr);
                
                match.attrs.push({
                    name: attr[1],
                    value: attr[3] || attr[4] || attr[5]
                })
                // 截取html，删除已经匹配过的标签
                advance(attr[0].length);
            }
            // 如果匹配到结束标签 >
            if (end){
                console.log(end);
                // 属性已经匹配完毕，截取html，删除已经匹配过的标签
                advance(end[0].length);
                console.log(match);
                
                return match
            }

        }
        
        // return match // 返回tag的属性
    }

    function start(tarName,attrs){
        console.log('开始-----------------------');
        const element = createASTlement(tarName,attrs);
        if (!root){
            root = element; // 根节点如果没有，则赋值给根节点
        }

        currentParent = element;  // 当前节点赋值给父节点
        stack.push(element); // 将节点推入栈中
        
        console.log(tarName,attrs);
    }
    
    function end(tarName){
        console.log('结束-----------------------')
        const element = stack.pop(); //获取到当前节点 （因为最后一个节点就是结束的节点）
        currentParent = stack[stack.length - 1];
        if (currentParent){
            element.parent = currentParent; // 给当前节点设置父节点为当前节点的前一个
            currentParent.children.push(element); // 将当前节点推入父节点的children中
        }
        console.log(tarName);
    }
    function chars(text){
        console.log('文本-----------------------')
        text = text.trim(); // 去掉空格
        if(text.length >0){
            // 给父元素的children中添加文本节点
            currentParent.children.push({
                type:3, // 文本节点
                text
            })
        }

    }
    
    // 截取函数（截取html字符串）截取n个字符
    function advance(n){
        html = html.slice(n);
    }
    // 创建ast节点
    function createASTlement(tarName,attrs){
        return {
            tag:tarName,
            type:1, // 1表示元素  2表示属性  3表示文本
            children:[],
            attrs,
            parent
        }
    }
    return root;
}


export {
    parseHtmlToAst
}